package lx.util;

import java.text.MessageFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Description: TODO 时间工具类
 * @Author: 李星 lixing_java@163.com
 * @Date: 2019/10/10 21:26
 */
public class DateUtil {
    /*
     * @Description TODO Date转换为LocalDateTime
     * @Author 李星
     * @Date 2019/9/16 17:22
     * @Param [date 日期对象]
     * @return java.time.LocalDateTime
     */
    private static LocalDateTime convertDateToLDT(Date date) {
        //LocalDate localDate = localDateTime.toLocalDate();
        //LocalTime localTime = localDateTime.toLocalTime();
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /*
     * @Description TODO LocalDateTime转换为Date
     * @Author 李星
     * @Date 2019/9/16 17:22
     * @Param [localDateTime 日期对象]
     * @return java.util.Date
     */
    private static Date convertLDTToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /*
     * @Description TODO 按照field（年:ChronoUnit.YEARS、月、日、时、分、秒）为localDateTime加值
     * @Author 李星
     * @Date 2019/9/16 17:23
     * @Param [date, number, field]
     * @return java.util.Date
     */
    public static Date plus(Date date, long number, ChronoUnit field) {
        LocalDateTime localDateTime = convertDateToLDT(date);
        return convertLDTToDate(localDateTime.plus(number, field));
    }

    /*
     * @Description TODO 按照field（年:ChronoUnit.YEARS、月、日、时、分、秒）为localDateTime减值
     * @Author 李星
     * @Date 2019/9/16 17:23
     * @Param [date, number, field]
     * @return java.util.Date
     */
    public static Date minus(Date date, long number, ChronoUnit field) {
        LocalDateTime localDateTime = convertDateToLDT(date);
        return convertLDTToDate(localDateTime.minus(number, field));
    }

    /*
     * @Description TODO 按照field获取两个日期的的差（年:ChronoUnit.YEARS、月、日、时、分、秒）
     * @Author 李星
     * @Date 2019/9/16 17:23
     * @Param [start, end, field]
     * @return long
     */
    public static int betweenTwoDate(Date start, Date end, ChronoUnit field) {
        LocalDateTime startTime = convertDateToLDT(start);
        LocalDateTime endTime = convertDateToLDT(end);
        Period period = Period.between(LocalDate.from(startTime), LocalDate.from(endTime));
        if (field == ChronoUnit.YEARS) return period.getYears();
        if (field == ChronoUnit.MONTHS) return period.getYears() * 12 + period.getMonths();
        return (int)field.between(startTime, endTime);
    }

    /*
     * @Description TODO dateCharacter日期字符串转化成日期对象
     * @Author 李星
     * @Date 2019/9/16 17:23
     * @Param [dateCharacter 格式：yyyy-MM-dd | yyyy-MM-dd HH:mm:ss ]
     * @return java.util.Date
     */
    public static Date dateCharacterToDate(String dateCharacter) throws Exception {
        try {
            if (dateCharacter.matches("^\\d{4}-\\d{1,2}-\\d{1,2}$")) {
                LocalDate localDate = LocalDate.parse(dateCharacter, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
                return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
            } else if (dateCharacter.matches("^\\d{4}-\\d{1,2}-\\d{1,2} \\d{1,2}:\\d{1,2}:\\d{1,2}$")) {
                LocalDateTime localDateTime = LocalDateTime.parse(dateCharacter, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                return convertLDTToDate(localDateTime);
            } else {
                throw new Exception(MessageFormat.format("{0}不是有效的日期字符串", dateCharacter));
            }
        } catch (Exception e) {
            throw new Exception(MessageFormat.format("{0}日期字符串转化成日期对象出错!", dateCharacter));
        }
    }

    /**
     * @Description TODO date日期对象转化成dateTimeMillisecond日期字符串
     * @Author 李星
     * @Date 2020/2/2 21:47
     */
    public static String dateToDateTimeMillisecondCharacter(Date date) throws Exception {
        try {
            LocalDateTime localDateTime = convertDateToLDT(date);
            return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"));
        } catch (Exception e) {
            throw new Exception("日期对象转化成日期字符串出错");
        }
    }

    /*
     * @Description TODO date日期对象转化成dateTimeCharacter日期字符串
     * @Author 李星
     * @Date 2019/9/16 17:23
     * @Param [date]
     * @return java.lang.String
     */
    public static String dateToDateTimeCharacter(Date date) throws Exception {
        return dateToDateTimeMillisecondCharacter(date).substring(0, 19);
    }

    /*
     * @Description TODO date日期对象转化成dateCharacter日期字符串
     * @Author 李星
     * @Date 2019/9/16 17:24
     * @Param [date 日期对象]
     * @return java.lang.String
     */
    public static String dateToDateCharacter(Date date) throws Exception {
        return dateToDateTimeMillisecondCharacter(date).substring(0, 10);
    }

    // TODO 当前date所属月的最大的天数
    public static int getLastDayOfMonth(Date date) {
        LocalDateTime localDateTime = convertDateToLDT(date);
        localDateTime = localDateTime.with(TemporalAdjusters.lastDayOfMonth());
        return localDateTime.getDayOfMonth();
    }

    /*
     * @Description TODO 获取某段时间内的所有日期字符串（格式：YYYY-MM-dd）
     * @Author 李星
     * @Date 2019/7/17 10:48
     * @Param [start 日期对象, end 日期对象]
     * @return java.util.List<java.util.Date>
     */
    public static List<String> getAllDateForRegion(Date start, Date end) throws Exception {
        List<String> datePeriodList = new ArrayList<>();
        int length = (int) betweenTwoDate(start, end, ChronoUnit.DAYS) + 1;
        for (int i = 0; i < length; i++) {
            datePeriodList.add(dateToDateCharacter(start));
            start = plus(start, 1, ChronoUnit.DAYS);
        }
        return datePeriodList;
    }

    /*
     * @Description 长整型时间转成字符串日期
     * @Author 李星
     * @Date 2020/3/3 16:05
     * @Param [longTime] 
     * @return java.lang.String
     */
    public static String longTimeToDateTimeStr(long longTime) throws Exception {
        return dateToDateTimeCharacter(new Date(longTime*1000L));
    }
}
